package model.session;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import model.cnf.CNF;
import controller.xml.XMLBaliseFormat;

/**
 * <p>
 * A {@link SessionBlock} that represent a cnf.
 * </p>
 * <p>
 * You can access to all the operation that have been lunch using this cnf.
 * </p>
 * <p>
 * This class can be use a first block see {@link SessionBlock}.
 * </p>
 * 
 * @author GRONOWSKI Stephane svan001@aol.com
 * 
 *         igsat 2010
 * 
 */
public class CNFUse extends SessionBlock {

	private CNFUseStatus							status	= CNFUseStatus.TO_BE_DETERMINED;
	private CNF										cnf;

	private Map<PreprocessorExecutionBlock, CNFUse>	preproc	= new HashMap<PreprocessorExecutionBlock, CNFUse>();

	private Set<SolverExecutionBlock>				solver	= new HashSet<SolverExecutionBlock>();

	/**
	 * Create a cnfuse.
	 * 
	 * @param first
	 *            the first block see {@link SessionBlock}
	 * @param cnf
	 *            the cnf corresponding to the usecnf
	 */
	public CNFUse(SessionBlock first, CNF cnf) {
		super(first);

		if (cnf == null)
			throw new IllegalArgumentException();
		this.cnf = cnf;


	}

	/**
	 * Create a cnfuse use as a first block.
	 * 
	 * @param cnf
	 *            the cnf corresponding to the usecnf
	 */
	public CNFUse(CNF cnf) {
		super();

		if (cnf == null)
			throw new IllegalArgumentException();
		this.cnf = cnf;

	}

	/**
	 * Return the status.
	 * 
	 * @return the status
	 */
	public CNFUseStatus getStatus() {
		return status;
	}

	/**
	 * Set the status.
	 * 
	 * @param status
	 *            the status to set
	 */
	public void setStatus(CNFUseStatus status) {
		this.status = status;
	}

	/**
	 * Return the cnf that correspond to the CNFUSe.
	 * 
	 * @return the cnf that correspond to the CNFUSe.
	 */
	public CNF getCnf() {
		return cnf;
	}

	/**
	 * Set the CNF
	 * 
	 * @param cnf
	 *            the cnf to set
	 */
	public void setCnf(CNF cnf) {
		this.cnf = cnf;
	}

	/**
	 * Return the preprocessor that was executed on that CNF associate with the CNF that result.
	 * 
	 * @return the preprocessor that was executed on that CNF associate with the CNF that result
	 *         from this execution.
	 */
	public Map<PreprocessorExecutionBlock, CNFUse> getPreproc() {
		return preproc;
	}

	/**
	 * Return the solver that was executed on this CNF.
	 * 
	 * @return the solver that was executed on this CNF.
	 */
	public Set<SolverExecutionBlock> getSolver() {
		return solver;
	}

	/**
	 * Add the proprecessor to the list of preprocessor that was executed on that CNF.
	 * 
	 * @param preproc
	 *            the preprocesso to add.
	 * @param cnf
	 *            the CNF result.
	 */
	public void addPreproc(PreprocessorExecutionBlock preproc, CNFUse cnf) {
		this.preproc.put(preproc, cnf);
	}

	/**
	 * Add the solver to the list of solver that has been executed on that cnf.
	 * 
	 * @param solver
	 *            the solver to add.
	 */
	public void addSolver(SolverExecutionBlock solver) {
		this.solver.add(solver);
	}

	/**
	 * Remove the preprocessor to the list of preprocessor that has been executed on that cnf.
	 * 
	 * @param preproc
	 *            the preprocessor.
	 * @return the CNF that result from the execution of the preprocessor.
	 */
	public CNFUse removePreproc(PreprocessorExecutionBlock preproc) {
		if (!this.preproc.containsKey(preproc))
			throw new IllegalArgumentException();

		CNFUse res = this.preproc.remove(preproc);
		return res;
	}

	/**
	 * Remove the solver to the list of solver that has been executed on that cnf.
	 * 
	 * @param solver
	 *            the solver
	 */
	public void removeSolver(SolverExecutionBlock solver) {
		if (!this.solver.remove(solver))
			throw new IllegalArgumentException();
	}

	/**
	 * Export the data in XML
	 * 
	 * @param file
	 *            {@link BufferedWriter} to write
	 * @param directory
	 *            the directory where to store the exported cnf
	 * @throws IOException
	 */
	public void exportXML(BufferedWriter file, File directory) throws IOException {
		if (!directory.isDirectory())
			throw new IOException();

		// open
		// file.newLine();
		file.write("<" + XMLBaliseFormat.CNFUSE + ">");

		// cnf
		cnf.exportXML(file);

		// sessionblock
		super.exportXML(file);

		// status
		// file.newLine();
		file.write("<" + XMLBaliseFormat.CNFUSE_STATUS + ">");
		file.write(status.getXmlValue());
		// file.newLine();
		file.write("</" + XMLBaliseFormat.CNFUSE_STATUS + ">");


		// solvers
		for (SolverExecutionBlock sol : solver)
			sol.exportXML(file);

		// preproc
		for (PreprocessorExecutionBlock pre : preproc.keySet())
		{
			// nouveau preproc
			// file.newLine();
			file.write("<" + XMLBaliseFormat.PREPROC_CNFUSE + ">");

			pre.exportXML(file);
			preproc.get(pre).exportXML(file, directory);
			// file.newLine();
			file.write("</" + XMLBaliseFormat.PREPROC_CNFUSE + ">");
		}

		// close
		// file.newLine();
		file.write("</" + XMLBaliseFormat.CNFUSE + ">");

		// export cnf
		File res = null;
		if (cnf.getLastExportFile() != null)
			res = cnf.export(cnf.getLastExportFile().getName(), directory);
		else
			res = cnf.export(cnf.getFileName(), directory);

		if (res == null)
			throw new IOException();
	}
}
